#include "../include/eventLoop.h"
#include "../include/acceptor.h"
#include "../include/tcpConnection.h"
#include <unistd.h>
#include <iostream>
#include <sys/eventfd.h>

using std::cout;
using std::cerr;
using std::endl;

EventLoop::EventLoop(Acceptor & acceptor)
:_epfd(createEpollFd())
,_eventList(1024)
,_isLooping(false)
,_acceptor(acceptor)
,_conns()
,_eventFd(createEventFd())
,_pendings()
,_mutex()
{
	// 添加将listentFd放到红黑树上去
	addEpollReadFd(acceptor.fd());

	addEpollReadFd(_eventFd);
}

EventLoop::~EventLoop()
{
	close(_epfd);
	close(_eventFd);
}

void EventLoop::loop()
{
	_isLooping = true;
	while(_isLooping)
		waitEpollFd();
}

void EventLoop::unloop()
{
	_isLooping = false;
}

void EventLoop::waitEpollFd()
{
	int readyNum = 0;
	do
	{
		readyNum = epoll_wait(_epfd,&*_eventList.begin(),_eventList.size(),30000);
	}while(readyNum == -1 && errno == EINTR);
	
	if(readyNum == -1)
	{
		cout << "readyNum == -1\n" ;
		return;
	}
	else if(readyNum == 0)
		cout << "epoll wait timeout!\n";
	else
	{
		if(readyNum == (int)_eventList.size())
			_eventList.resize(2 * readyNum);
		
		for(int i = 0;i < readyNum;i++)
		{
			int fd = _eventList[i].data.fd;
			int listenFd = _acceptor.fd();
			if(fd == listenFd)
			{
				if(_eventList[i].events & EPOLLIN)
					handleNewConnection();
			}
			else if(fd == _eventFd)
			{
				// 有子线程完成了任务，执行子线程放入的任务
				handleRead();
				doPendingFunctors();
			}
			else
			{
				if(_eventList[i].events & EPOLLIN)
					handleMessage(fd);
			}
		}
	}
}

void EventLoop::setNewConnectionCallBack(function<void(const shared_ptr<TcpConnection>&)>&& callBack)
{
	_callBackNewConnection = callBack;
}

void EventLoop::setMessageCallBack(function<void(const shared_ptr<TcpConnection>&)>&& callBack)
{
	_callBackMessage = callBack;
}

void EventLoop::setCloseCallBack(function<void(const shared_ptr<TcpConnection>&)>&& callBack)
{
	_callBackClose = callBack;
}

void EventLoop::handleNewConnection()
{
	int newFd = _acceptor.accept();
	if(newFd < 0)
	{
		perror("handleNewConnection error");
		return;
	}
	// 将新连接放入红黑树监听
	addEpollReadFd(newFd);
	// 创建新的连接
	shared_ptr<TcpConnection> con(new TcpConnection(newFd,this));
	// 注册相关事件
	con->setNewConnectionCallBack(_callBackNewConnection);
	con->setMessageCallBack(_callBackMessage);
	con->setCloseCallBack(_callBackClose);
	// 将连接存放起来
	_conns.insert({newFd,con});
	// 执行连接建立事件
	con->handleNewConnectionCallBack();
}

void EventLoop::handleMessage(int fd)
{
	// 找到该文件描述符
	auto it = _conns.find(fd);
	if(it != _conns.end())
	{
		// 是否是客户端断开事件
		bool closeFlag = it->second->isClose();
		if(closeFlag)
		{
			// 执行断开事件
			it->second->handleCloseCallBack();
			// 取消该断开连接的监听
			delEpollReadFd(fd);	
			// 从map中删除
			_conns.erase(it);
		}
		else
		{
			// 处理客户端发来的消息
			it->second->handleMessageCallBack();
		}
	}
	else
	{
		cout << "该连接不存在\n";
		return;
	}
}

int EventLoop::createEpollFd()
{
	int fd = epoll_create(1);
	if(fd < 0)
	{
		perror("createEpollFd");
		return -1;
	}
	return fd;
}

void EventLoop::addEpollReadFd(int fd)
{
	struct epoll_event event;
	event.data.fd = fd;
	event.events = EPOLLIN;

	int ret = epoll_ctl(_epfd,EPOLL_CTL_ADD,fd,&event);
	if(ret < 0)
	{
		perror("addEpollReadFd error!\n");
		return;
	}
}

void EventLoop::delEpollReadFd(int fd)
{
	struct epoll_event event;
	event.data.fd = fd;
	event.events = EPOLLIN;
	
	int ret = epoll_ctl(_epfd,EPOLL_CTL_DEL,fd,&event);
	if(ret < 0)
	{
		perror("delEpollReadFd error!\n");
		return;
	}
}

void EventLoop::handleRead()
{
	uint64_t one = 1;
	ssize_t ret = read(_eventFd,&one,sizeof(uint64_t));
	if(ret != sizeof(uint64_t))
	{
		perror("handleRead error!\n");
		return;
	}
}

void EventLoop::wakeUp()
{
	uint64_t one = 1;
	ssize_t ret = write(_eventFd,&one,sizeof(uint64_t));
	if(ret != sizeof(uint64_t))
	{
		perror("wakeUp error!\n");
		return;
	}
}

int EventLoop::createEventFd()
{
	int fd = eventfd(0,0);
	if(fd < 0)
	{
		perror("createEventFd error!\n");
		return -1;
	}
	return fd;
}

void EventLoop::doPendingFunctors()
{
	// 减小临界区
	vector<function<void()>> temp;
	{
		lock_guard<mutex> lg(mutex);
		temp.swap(_pendings);
	}

	for(auto & cb : temp)
		cb();
}

void EventLoop::runInLoop(function<void()> && callBack)
{
	{
		lock_guard<mutex> lg(mutex);
		_pendings.push_back(std::move(callBack));
	}

	wakeUp();
}







